﻿using Furion;
using Furion.DatabaseAccessor;
using Furion.DataEncryption;
using Furion.DistributedIDGenerator;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Furion.Core;
using Furion.Core.Entities.Enums;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using StackExchange.Profiling.Internal;
using System.Drawing;
using System.Xml.Linq;
using System.Reflection;
using Furion.InstantMessaging;

namespace Furion.Application
{
    
    [AppAuthorize, ApiDescriptionSettings("Business", Name = "File", Order = 2, Tag = "文件上传")]
    public class FileService: IDynamicApiController
    {
        private readonly IRepository<SysFile> _sysFileRepository;
        private readonly IAuthorizationManager _authorizationManager;
        private readonly IHttpContextAccessor _httpContextAccessor;
        public FileService(IRepository<SysFile> sysFileRepository, IAuthorizationManager authorizationManager, IHttpContextAccessor httpContextAccessor)
        {
            _sysFileRepository = sysFileRepository;
            _authorizationManager = authorizationManager;
            _httpContextAccessor = httpContextAccessor;
        }

        /// <summary>
        /// 测试
        /// </summary>
        /// <returns></returns>
        [AllowAnonymous, HttpGet("/File/Test"), ApiDescriptionSettings(Name = "Upload"), NonUnify]
        public string TestApi()
        {
            return $"{Assembly.GetExecutingAssembly().FullName};IP:{HttpContextExtensions.GetRemoteIpAddressToIPv4(_httpContextAccessor.HttpContext)};当前时间：{DateTime.Now:G};Port：{App.Configuration["ConsulRegisterOptions:Port"]}";
        }


        /// <summary>
        /// 文件上传
        /// </summary>
        /// <param name="files"></param>
        /// <returns></returns>
        [SecurityDefine(ConstPermission.File_Upload), HttpPost("/File/Upload"), ApiDescriptionSettings(Name = "Upload"), NonUnify]
        public async Task<List<SysFile>> UploadAsync(List<IFormFile> files)
        {
            string FileHost = App.Configuration["FileUpload:FileHost"];//"http://" + App.Configuration["ConsulRegisterOptions:Ip"] + ":" + App.Configuration["ConsulRegisterOptions:Port"]; //

            // 网站根目录wwwroot目录
            string absolutely_path = App.WebHostEnvironment.WebRootPath;
            string temp_path = App.Configuration["FileUpload:UploadDir"];

            //var savePath = Path.Combine(App.HostEnvironment.ContentRootPath, temp_path);
            var savePath = Path.Combine(absolutely_path, temp_path);
            if (!Directory.Exists(savePath)) Directory.CreateDirectory(savePath);

            var datePath = Path.Combine(savePath, DateTime.Now.ToString("yyyyMMdd"));
            if (!Directory.Exists(datePath)) Directory.CreateDirectory(datePath);

            List<string> arr = new List<string>();
            List<SysFile> list = new List<SysFile>();
            foreach (var formFile in files)
            {
                           
                if (formFile.Length > 0)
                {
                    var file = new SysFile();

                    file.Id= Yitter.IdGenerator.YitIdHelper.NextId();
                    file.FileLength = Convert.ToInt32(formFile.Length / 1024);
                    file.OriginName = Path.GetFileName(formFile.FileName);
                    file.ExtName= Path.GetExtension(formFile.FileName);
                    file.FileName = file.Id.ToString() + file.ExtName;
                    file.FilePath = "/" + temp_path + "/" + DateTime.Now.ToString("yyyyMMdd") + "/" + file.FileName;
                    file.WebPath= FileHost + "/" + temp_path + "/" + DateTime.Now.ToString("yyyyMMdd") + "/" + file.FileName;
                    file.CreatedTime=DateTime.Now;
                    file.CreatedUserId = _authorizationManager.UserId;
                    file.CreatedUserName = _authorizationManager.Name;
                                        
                    var filePath = Path.Combine(datePath, file.FileName);  // 可以替代为你需要存储的真实路径
                    using (var stream = System.IO.File.Create(filePath))
                    {
                        await formFile.CopyToAsync(stream);
                    }

                    list.Add(file);
                }
            }
            await _sysFileRepository.InsertNowAsync(list);
            return list;
        }

        /// <summary>
        /// 图片上传
        /// </summary>
        /// <param name="files"></param>
        /// <returns></returns>
        [SecurityDefine(ConstPermission.File_Upload), HttpPost("/File/UploadImage"), ApiDescriptionSettings(Name = "UploadImage"), NonUnify]
        public async Task<List<SysFile>> UploadImageAsync(List<IFormFile> files)
        {
            string FileHost = App.Configuration["FileUpload:FileHost"];

            int ThumbWidth = 800;
            if (App.Configuration["FileUpload:ThumbWidth"].HasValue())
            {
                ThumbWidth = Convert.ToInt32(App.Configuration["FileUpload:ThumbWidth"]);
            }
            int ThumbHeight = 600;
            if (App.Configuration["FileUpload:ThumbHeight"].HasValue())
            {
                ThumbHeight = Convert.ToInt32(App.Configuration["FileUpload:ThumbHeight"]);
            }
            string ThumbMode = App.Configuration["FileUpload:ThumbMode"];


            // 网站根目录wwwroot目录
            string absolutely_path = App.WebHostEnvironment.WebRootPath;
            string temp_path = App.Configuration["FileUpload:UploadDir"];

            //var savePath = Path.Combine(App.HostEnvironment.ContentRootPath, temp_path);
            var savePath = Path.Combine(absolutely_path, temp_path);
            if (!Directory.Exists(savePath)) Directory.CreateDirectory(savePath);

            var datePath = Path.Combine(savePath, DateTime.Now.ToString("yyyyMMdd"));
            if (!Directory.Exists(datePath)) Directory.CreateDirectory(datePath);

            List<string> arr = new List<string>();
            List<SysFile> list = new List<SysFile>();
            foreach (var formFile in files)
            {                
                if (formFile.Length > 0)
                {
                    var file = new SysFile();
                    file.Id = Yitter.IdGenerator.YitIdHelper.NextId();
                    file.FileLength = Convert.ToInt32(formFile.Length / 1024);
                    file.OriginName = Path.GetFileName(formFile.FileName);
                    file.ExtName = Path.GetExtension(formFile.FileName);
                    file.FileName = file.Id.ToString() + file.ExtName;
                    file.FilePath = "/" + temp_path + "/" + DateTime.Now.ToString("yyyyMMdd") + "/" + file.FileName;
                    file.WebPath = FileHost + "/" + temp_path + "/" + DateTime.Now.ToString("yyyyMMdd") + "/" + file.FileName;
                    file.CreatedTime = DateTime.Now;
                    file.CreatedUserId = _authorizationManager.UserId;
                    file.CreatedUserName = _authorizationManager.Name;

                    var filePath = Path.Combine(datePath, file.FileName);  // 可以替代为你需要存储的真实路径
                    using (var stream = System.IO.File.Create(filePath))
                    {
                        await formFile.CopyToAsync(stream);
                    }

                    string ThumbFileName= file.Id.ToString() + "_thumb" + file.ExtName;
                    var ThumbFilePath = Path.Combine(datePath, ThumbFileName);
                    if (Helper.MakeThumbnail(filePath, ThumbFilePath, ThumbWidth, ThumbHeight, ThumbMode))
                    {
                        file.FilePath = "/" + temp_path + "/" + DateTime.Now.ToString("yyyyMMdd") + "/" + ThumbFileName;
                        file.WebPath = FileHost + "/" + temp_path + "/" + DateTime.Now.ToString("yyyyMMdd") + "/" + ThumbFileName;
                    }
                    else
                    {
                        if (file.ExtName == ".png")
                        {
                            ThumbFileName = file.Id.ToString() + "_thumb" + ".jpg";
                            ThumbFilePath = Path.Combine(datePath, ThumbFileName);
                            if(System.OperatingSystem.IsWindows())
                            {
                                System.Drawing.Image img = System.Drawing.Image.FromFile(filePath);
                                using (var b = new System.Drawing.Bitmap(img.Width, img.Height))
                                {
                                    b.SetResolution(img.HorizontalResolution, img.VerticalResolution);
                                    using (var g = System.Drawing.Graphics.FromImage(b))
                                    {
                                        g.Clear(System.Drawing.Color.White);
                                        g.DrawImageUnscaled(img, 0, 0);
                                    }
                                    b.Save(ThumbFilePath, System.Drawing.Imaging.ImageFormat.Jpeg);
                                }
                            }
                            else
                            {
                                using var image = SixLabors.ImageSharp.Image.Load(filePath);
                                image.Mutate(x => x.Resize(image.Width / 2, image.Height / 2));
                                image.Save(ThumbFilePath);
                            }
                            
                            file.FilePath = "/" + temp_path + "/" + DateTime.Now.ToString("yyyyMMdd") + "/" + ThumbFileName;
                            file.WebPath = FileHost + "/" + temp_path + "/" + DateTime.Now.ToString("yyyyMMdd") + "/" + ThumbFileName;
                        }
                    }
                    list.Add(file);
                }
            }
            await _sysFileRepository.InsertNowAsync(list);
            return list;
        }



        /// <summary>
        /// 文件上传(安全)
        /// </summary>
        /// <param name="files"></param>
        /// <returns></returns>

        [SecurityDefine(ConstPermission.File_Upload), HttpPost("/File/UploadSafe"), ApiDescriptionSettings(Name = "UploadSafe"), NonUnify]

        public async Task<List<SysFile>> UploadSafeAsync(List<IFormFile> files)
        {
            string FileHost =App.Configuration["FileUpload:FileHost"]; //"http://" + App.Configuration["ConsulRegisterOptions:Ip"] + ":" + App.Configuration["ConsulRegisterOptions:Port"];

            // 保存到网站根目录下的 uploads 目录
            string absolutely_path= App.Configuration["FileUpload:AbsolutelySecurityPath"];
            string temp_path = App.Configuration["FileUpload:UploadSecurityDir"];

            //var savePath = Path.Combine(App.HostEnvironment.ContentRootPath, temp_path);
            var savePath = Path.Combine(absolutely_path,temp_path);
            if (!Directory.Exists(savePath)) Directory.CreateDirectory(savePath);

            var datePath = Path.Combine(savePath, DateTime.Now.ToString("yyyyMMdd"));
            if (!Directory.Exists(datePath)) Directory.CreateDirectory(datePath);

            List<SysFile> list = new List<SysFile>();
            foreach (var formFile in files)
            {
                if (formFile.Length > 0)
                {
                    var file = new SysFile();
                    file.Id = Yitter.IdGenerator.YitIdHelper.NextId();
                    file.FileLength = Convert.ToInt32(formFile.Length / 1024);
                    file.OriginName = Path.GetFileName(formFile.FileName);
                    file.ExtName = Path.GetExtension(formFile.FileName);
                    file.FileName = file.Id.ToString() + file.ExtName;
                    file.FilePath = "/" + temp_path + "/" + DateTime.Now.ToString("yyyyMMdd") + "/" + file.FileName;
                    file.WebPath = FileHost + "/File/Download?Id="+ file.Id;
                    file.CreatedTime = DateTime.Now;
                    file.CreatedUserId = _authorizationManager.UserId;
                    file.CreatedUserName = _authorizationManager.Name;

                    // 避免文件名重复，采用 GUID 生成
                    var filePath = Path.Combine(datePath, file.FileName);  // 可以替代为你需要存储的真实路径
                    using (var stream = System.IO.File.Create(filePath))
                    {
                        await formFile.CopyToAsync(stream);
                    }
                    list.Add(file);
                }                
            }
            await _sysFileRepository.InsertNowAsync(list);
            return list;
        }


        /// <summary>
        /// 图片上传(安全)
        /// </summary>
        /// <param name="files"></param>
        /// <returns></returns>

        [SecurityDefine(ConstPermission.File_Upload), HttpPost("/File/UploadImageSafe"), ApiDescriptionSettings(Name = "UploadImageSafe"), NonUnify]

        public async Task<List<SysFile>> UploadImageSafeAsync(List<IFormFile> files)
        {
            string FileHost = App.Configuration["FileUpload:FileHost"]; 
            int ThumbWidth = 800;
            if (App.Configuration["FileUpload:ThumbWidth"].HasValue())
            {
                ThumbWidth = Convert.ToInt32(App.Configuration["FileUpload:ThumbWidth"]);
            }
            int ThumbHeight = 600;
            if (App.Configuration["FileUpload:ThumbHeight"].HasValue())
            {
                ThumbHeight = Convert.ToInt32(App.Configuration["FileUpload:ThumbHeight"]);
            }
            string ThumbMode = App.Configuration["FileUpload:ThumbMode"];


            // 保存到网站根目录下的 uploads 目录
            string absolutely_path = App.Configuration["FileUpload:AbsolutelySecurityPath"];
            string temp_path = App.Configuration["FileUpload:UploadSecurityDir"];

            //var savePath = Path.Combine(App.HostEnvironment.ContentRootPath, temp_path);
            var savePath = Path.Combine(absolutely_path, temp_path);
            if (!Directory.Exists(savePath)) Directory.CreateDirectory(savePath);

            var datePath = Path.Combine(savePath, DateTime.Now.ToString("yyyyMMdd"));
            if (!Directory.Exists(datePath)) Directory.CreateDirectory(datePath);

            List<SysFile> list = new List<SysFile>();
            foreach (var formFile in files)
            {
                if (formFile.Length > 0)
                {
                    var file = new SysFile();
                    file.Id = Yitter.IdGenerator.YitIdHelper.NextId();
                    file.FileLength = Convert.ToInt32(formFile.Length / 1024);
                    file.OriginName = Path.GetFileName(formFile.FileName);
                    file.ExtName = Path.GetExtension(formFile.FileName);
                    file.FileName = file.Id.ToString() + file.ExtName;
                    file.FilePath = "/" + temp_path + "/" + DateTime.Now.ToString("yyyyMMdd") + "/" + file.FileName;
                    file.WebPath = FileHost + "/File/ShowImage?Id=" + file.Id;
                    file.CreatedTime = DateTime.Now;
                    file.CreatedUserId = _authorizationManager.UserId;
                    file.CreatedUserName = _authorizationManager.Name;

                    // 避免文件名重复，采用 GUID 生成
                    var filePath = Path.Combine(datePath, file.FileName);  // 可以替代为你需要存储的真实路径
                    using (var stream = System.IO.File.Create(filePath))
                    {
                        await formFile.CopyToAsync(stream);
                    }


                    string ThumbFileName = file.Id.ToString() + "_thumb" + file.ExtName;
                    var ThumbFilePath = Path.Combine(datePath, ThumbFileName);
                    if (Helper.MakeThumbnail(filePath, ThumbFilePath, ThumbWidth, ThumbHeight, ThumbMode))
                    {
                        file.FilePath = "/" + temp_path + "/" + DateTime.Now.ToString("yyyyMMdd") + "/" + ThumbFileName;
                    }
                    else
                    {
                        if (file.ExtName == ".png")
                        {
                            ThumbFileName = file.Id.ToString() + "_thumb" + ".jpg";
                            ThumbFilePath = Path.Combine(datePath, ThumbFileName);

                            if (System.OperatingSystem.IsWindows())
                            {
                                System.Drawing.Image img = System.Drawing.Image.FromFile(filePath);
                                using (var b = new System.Drawing.Bitmap(img.Width, img.Height))
                                {
                                    b.SetResolution(img.HorizontalResolution, img.VerticalResolution);
                                    using (var g = System.Drawing.Graphics.FromImage(b))
                                    {
                                        g.Clear(System.Drawing.Color.White);
                                        g.DrawImageUnscaled(img, 0, 0);
                                    }
                                    b.Save(ThumbFilePath, System.Drawing.Imaging.ImageFormat.Jpeg);
                                }
                            }
                            else
                            {
                                using var image = SixLabors.ImageSharp.Image.Load(filePath);
                                image.Mutate(x => x.Resize(image.Width / 2, image.Height / 2));
                                image.Save(ThumbFilePath);
                            }
                            file.FilePath = "/" + temp_path + "/" + DateTime.Now.ToString("yyyyMMdd") + "/" + ThumbFileName;
                        }
                    }
                    list.Add(file);
                }
            }
            await _sysFileRepository.InsertNowAsync(list);
            return list;
        }


        /// <summary>
        /// 文件下载
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        [SecurityDefine(ConstPermission.File_Download), HttpGet("/File/Download"), ApiDescriptionSettings(Name = "Download"), NonUnify]
        public async Task<IActionResult> DownloadAsync([Required]long Id)
        {
            var val = await _sysFileRepository.DetachedEntities.AnyAsync(a=>a.Id==Id);
            if (val)
            {
                var file = await _sysFileRepository.DetachedEntities.Where(a => a.Id == Id).FirstOrDefaultAsync();
                string absolutely_path = App.Configuration["FileUpload:AbsolutelySecurityPath"];
                var savePath = absolutely_path + file.FilePath;
                return  new FileStreamResult(new FileStream(savePath, FileMode.Open), "application/octet-stream") { FileDownloadName = file.OriginName };
            }
            else
            {
                return new EmptyResult();
            }             
        }


        /// <summary>
        /// 显示图片
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        [SecurityDefine(ConstPermission.File_Download), HttpGet("/File/Image"), ApiDescriptionSettings(Name = "Image"), NonUnify]
        public async Task<string> ImageAsync([Required] long Id)
        {
            var val = await _sysFileRepository.DetachedEntities.AnyAsync(a => a.Id == Id);
            if (val)
            {
                var file =await _sysFileRepository.DetachedEntities.Where(a => a.Id == Id).FirstOrDefaultAsync();
                string absolutely_path = App.Configuration["FileUpload:AbsolutelySecurityPath"];
                var savePath = absolutely_path + file.FilePath;

                FileStream fs = new FileStream(savePath, FileMode.Open, FileAccess.Read);
                byte[] data = new byte[(int)fs.Length];
                fs.Read(data, 0, data.Length);
                string Base64Image = "data:image/png;base64," + Convert.ToBase64String(data);
                return Base64Image;
            }
            else
            {
                return "";
            }
        }



        /// <summary>
        /// 大文件分片上传
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [AllowAnonymous, HttpPost("/File/UploadBigFile"), ApiDescriptionSettings(Name = "UploadBigFile"), NonUnify]
        public async Task<BigFileOutput> UploadBigFile([FromForm] BigFileInput input)
        {
            string FileHost = App.Configuration["FileUpload:FileHost"];

            _httpContextAccessor.HttpContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");

            string AbsolutelySecurityPath = App.WebHostEnvironment.WebRootPath;
            string UploadBigDir = App.Configuration["FileUpload:UploadBigDir"];

            string dir_path = Path.Combine(AbsolutelySecurityPath,App.Configuration["FileUpload:UploadBigDir"],input.TempDir);

            if (!Directory.Exists(dir_path))
                Directory.CreateDirectory(dir_path);

            string filePath = Path.Combine(dir_path, input.FileIndex.ToString());
            if (!Convert.IsDBNull(input.Data))
            {
                await Task.Run(() =>
                {
                    using (FileStream fs = new FileStream(filePath, FileMode.Create))
                    {
                        input.Data.CopyTo(fs);
                    }
                });
            }

            
            string final_dir = Path.Combine(AbsolutelySecurityPath, UploadBigDir, DateTime.Now.ToString("yyyyMMdd"));
            if (!Directory.Exists(final_dir))
            {
                Directory.CreateDirectory(final_dir);
            }


            

            bool IsMerge = false;
            if (input.Total == input.FileIndex)
            {
                //最终文件名
                string fileExt = Path.GetExtension(input.FileName);
                string file_name = Yitter.IdGenerator.YitIdHelper.NextId() + fileExt;
                string final_file = Path.Combine(final_dir, file_name);
                string web_path = FileHost + "/" + UploadBigDir + "/" + DateTime.Now.ToString("yyyyMMdd") + "/" + file_name;
                IsMerge = await FileMerge(dir_path, final_file);

                var file = new SysFile();
                file.Id = Yitter.IdGenerator.YitIdHelper.NextId();
                file.FileLength = Convert.ToInt32( input.Total*1024);
                file.OriginName = input.FileName;
                file.ExtName = fileExt;
                file.FileName = file.Id.ToString() + file.ExtName;
                file.FilePath = final_file;
                file.WebPath = web_path;
                file.CreatedTime = DateTime.Now;
                file.CreatedUserId = _authorizationManager.UserId;
                file.CreatedUserName = _authorizationManager.Name;
                await _sysFileRepository.InsertNowAsync(file);

                var output = new BigFileOutput { CurrentIndex = input.FileIndex, IsMerge = IsMerge, WebPath = web_path };
                return output;
            }
            else
            {
                var output = new BigFileOutput { CurrentIndex = input.FileIndex, IsMerge = IsMerge, WebPath = "" };
                return output;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="temporary">临时缓存文件夹</param>
        /// <param name="final_file">最终生成文件路径</param>
        /// <returns></returns>
        [ApiDescriptionSettings(false)]
        public async Task<bool> FileMerge(string temporary, string final_file)
        {
            bool ok = false;
            var files = Directory.GetFiles(temporary);
            using (var fs = new FileStream(final_file, FileMode.Create))
            {
                foreach (var part in files.OrderBy(x => x.Length).ThenBy(x => x))//排一下序，保证从0-N Write
                {
                    var bytes = System.IO.File.ReadAllBytes(part);
                    await fs.WriteAsync(bytes, 0, bytes.Length);
                    bytes = null;
                    System.IO.File.Delete(part);//删除分块
                }
                fs.Close();
                Directory.Delete(temporary);//删除文件夹
                ok = true;
            }

            return ok;
        }




    }
}
